package ycl.common.base.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ycl.common.base.entity.BaseEntity;
import ycl.common.base.mapper.BaseDao;
import ycl.common.base.service.BaseService;
import ycl.common.constants.RedisConstant;
import ycl.common.constants.SecurityConstant;
import ycl.common.result.REnum;
import ycl.common.exception.CustomException;
import ycl.common.models.BaseEntityRes;
import ycl.common.models.req.BaseReq;
import ycl.common.models.res.LoginUser;
import ycl.common.utils.AnnotationUtil;
import ycl.common.utils.BaseEntityUtil;
import ycl.common.utils.JSONObjectConvertUtil;
import ycl.common.utils.PageUtil;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 逻辑层基类处理
 *
 * @author YCL
 * @date 2021-06-05 00:00:33
 */
@Service
@Lazy
public abstract class BaseServiceImpl<M extends BaseDao<T>,
		T extends BaseEntity,
		Q extends BaseReq,
		R extends BaseEntityRes>
		extends ServiceImpl<M, T>
		implements BaseService<T, Q, R> {

	@Autowired//无法使用@Resource
	protected BaseDao<T> baseDao;
	@Resource
	protected StringRedisTemplate stringRedisTemplate;


	@Override
	public Page<R> pageList(HttpServletRequest request, T t, Class<R> c) {
		Page<T> page = PageUtil.getPage(t, t.getClass());
		Class<? extends BaseEntity> clazz = t.getClass();
		String tableName = AnnotationUtil.getTableName(clazz);
		List<T> list = this.baseDao.findPage(tableName, page, t);
		page.setRecords(list);
		return BaseEntityUtil.pageCast(page, c);
	}

	@Override
	public T getById(HttpServletRequest request, Long id, Class<T> c) {
		Assert.notNull(id, "请传入id");
		if (!BaseEntityUtil.hasField(c, "userId"))
			return null;
		String token = request.getHeader(SecurityConstant.TOKEN);
		String v = stringRedisTemplate.opsForValue().get(RedisConstant.getLoginUserKey(token));
		if (StrUtil.isBlank(v))
			return null;
		LoginUser user = JSONObject.parseObject(v, LoginUser.class);
		Long userId = user.getId();
		String tableName = AnnotationUtil.getTableName(c);
		return baseDao.selectByIdUserId(id, userId, tableName);
	}


	/**
	 * 获取用户id, 用户必登录, 否则报错
	 *
	 * @param request 用户登录信息
	 * @return 用户id
	 */
	protected Long getUserId(HttpServletRequest request) {
		return getUserId(request, true);
	}

	/**
	 * 获取用户id, 用户如果没有登录就返回 null
	 *
	 * @param request 用户登录信息
	 * @return 用户id
	 */
	protected Long getUserIdNotThrow(HttpServletRequest request) {
		return getUserId(request, false);
	}

	private Long getUserId(HttpServletRequest request, boolean thr) {
		String token = request.getHeader(SecurityConstant.TOKEN);
		String v = stringRedisTemplate.opsForValue().get(RedisConstant.getLoginUserKey(token));
		if (StrUtil.isBlank(v)) {
			if (thr)
				throw new CustomException(REnum.USED_UNAUTHORIZED);
			else
				return null;
		}
		LoginUser user = JSONObject.parseObject(v, LoginUser.class);
		return user.getId();
	}


	@Override
	@Transactional
	public void save(HttpServletRequest request, Q q, Class<T> t) {
		T convert = JSONObjectConvertUtil.convert(q, t);
		convert.setId(null);
		baseDao.insert(convert);
	}


	@Override
	@Transactional
	public void update(HttpServletRequest request, Q q, Class<T> t) {
		Assert.notNull(q.getId(), "请传入id");
		T convert = JSONObjectConvertUtil.convert(q, t);
		baseDao.updateById(convert);
	}
}
